The high-level touch interface in Silverlight involves three events: ManipulationStarted, ManipulationDelta, and ManipulationCompleted.
These events don’t bother with reporting the activity of individual
fingers. Instead, they consolidate the activity of multiple fingers into
translation and scaling operations. The events also accumulate velocity information, so while they don’t support inertia directly, they can be used to implement inertia.
The Manipulation events will receive more coverage in the chapters ahead. In this chapter I’m going to stick with ManipulationStarted just to detect contact of a finger on the screen, and I won’t bother with what the finger does after that.
While Touch.FrameReported delivered touch information for the entire application, the Manipulation events are based on individual elements, so in SilverlightTapHello1, a ManipulationStarted event handler can be set on the TextBlock:
Example 1. Silverlight Project: SilverlightTapHello1 File: MainPage.xaml (excerpt)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <TextBlock Text="Hello, Windows Phone 7!" Padding="0 34" HorizontalAlignment="Center" VerticalAlignment="Center" ManipulationStarted="OnTextBlockManipulationStarted" /> </Grid>
|
The MainPage.xaml.cs contains this event handler:
Example 2. Silverlight Project: SilverlightTapHello1 File: MainPage.xaml.cs (excerpt)
public partial class MainPage : PhoneApplicationPage { Random rand = new Random();
public MainPage() { InitializeComponent(); } void OnTextBlockManipulationStarted(object sender, ManipulationStartedEventArgs args) { TextBlock txtblk = sender as TextBlock;
Color clr = Color.FromArgb(255, (byte)rand.Next(256), (byte)rand.Next(256), (byte)rand.Next(256));
txtblk.Foreground = new SolidColorBrush(clr);
args.Complete(); } }
|
The event handler is able to get the element generating the message from the sender argument. That will always be the TextBlock. The TextBlock is also available from the args.OriginalSource property and the args.ManipulationContainer property.
Notice the call to the Complete method of the event arguments at the end. This is not required but effectively tells the system that further Manipulation events involving this finger won’t be necessary.
This program is flawed: If you try it out, you’ll see that it works only partially. Touching the TextBlock changes the text to a random color. But if you touch outside the TextBlock, the text does not go back to white. Because this event was set on the TextBlock, the event handler is called only when the user touches the TextBlock. No other Manipulation events are processed by the program.
A program that functions correctly according to my original specification needs to get touch events occurring anywhere on the page. A handler for the ManipulationStarted event needs to be installed on MainPage rather than just on the TextBlock.
Although that’s certainly possible, there’s actually an easier way. The UIElement class defines all the Manipulation events. But the Control class (from which MainPage derives) supplements those events with protected virtual methods. You don’t need to install a handler for the ManipulationStarted event on MainPage; instead you can override the OnManipulationStarted virtual method.
This approach is implemented in the SilverlightTapHello2 project. The XAML file doesn’t refer to any events but gives the TextBlock a name so that it can be referred to in code:
Example 3. Silverlight Project: SilverlightTapHello2 File: MainPage.xaml (excerpt)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <TextBlock Name="txtblk" Text="Hello, Windows Phone 7!" Padding="0 34" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid>
|
The MainPage class overrides the OnManipulationStarted method:
Example 4. Silverlight Project: SilverlightTapHello2 File: MainPage.xaml.cs (excerpt)
public partial class MainPage : PhoneApplicationPage { Random rand = new Random(); Brush originalBrush;
public MainPage() { InitializeComponent(); originalBrush = txtblk.Foreground; }
protected override void OnManipulationStarted(ManipulationStartedEventArgs args) { if (args.OriginalSource == txtblk) { txtblk.Foreground = new SolidColorBrush( Color.FromArgb(255, (byte)rand.Next(256), (byte)rand.Next(256), (byte)rand.Next(256))); } else { txtblk.Foreground = originalBrush; }
args.Complete(); base.OnManipulationStarted(args); } }
|
In the ManipulationStartedEventArgs a property named OriginalSource indicates where this event began—in other words, the topmost element that the user tapped. If this equals the txtblk object, the method creates a random color for the Foreground property. If not, then the Foreground property is set to the original brush.
In this OnManiulationStarted method we’re handling events for MainPage, but that OriginalSource
property tells us the event actually originated lower in the visual
tree. This is part of the benefit of the Silverlight feature known as routed event handling.